{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 特殊用途函数\n",
    "\n",
    "1. __str__和__repr__\n",
    "3. __iter__\n",
    "4. __getitem__\n",
    "5. __getattr__\n",
    "6. __call__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `__str__`和`__repr__`\n",
    "\n",
    "1. `__str__`:返回用户看到的字符串，可以设置显示的样式；\n",
    "2. `__repr__`:返回调试信息的字符串；"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Student1:  <__main__.Student1 object at 0x000001C2F8329A20>\n",
      "Student11:  Student11 object (name=MIch)\n",
      "Student2:  Student2 object (name: Zach)\n"
     ]
    }
   ],
   "source": [
    "class Student1(object):\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "        \n",
    "# 改写__repr__函数\n",
    "# 通常__str__和__repr__是一样的\n",
    "class Student11(object):\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "        \n",
    "    def __str__(self):\n",
    "        return \"Student11 object (name=%s)\" % self.name\n",
    "    \n",
    "    __repr__ = __str__\n",
    "        \n",
    "\n",
    "# 在类class中添加__str__()函数\n",
    "class Student2(object):\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "        \n",
    "    def __str__(self):\n",
    "        return \"Student2 object (name: %s)\" % self.name\n",
    "    \n",
    "    \n",
    "print(\"Student1: \", Student1(\"Mich\")) # 默认调用__repr__函数\n",
    "print(\"Student11: \", Student11(\"MIch\")) # 调用__str__函数\n",
    "print(\"Student2: \", Student2(\"Zach\")) # 调用__str__函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `__iter__`\n",
    "\n",
    "`__iter__`方法使得一个类成为可迭代对象。Python的for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值，直到遇到`StopIteration`错误时退出循环。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 "
     ]
    }
   ],
   "source": [
    "class Fib(object):\n",
    "    def __init__(self):\n",
    "        self.a, self.b = 0, 1 # 初始化两个计数\n",
    "        \n",
    "    def __iter__(self):\n",
    "        return self # 实例本身就是迭代对象\n",
    "    \n",
    "    def __next__(self):\n",
    "        self.a, self.b = self.b, self.a + self.b # 计算下一个值\n",
    "        if self.a > 100000: # 退出循环的条件\n",
    "            raise StopIteration()\n",
    "        return self.a\n",
    "    \n",
    "    \n",
    "for n in Fib(): # Fib成了一个迭代器\n",
    "    print(n,end=\" \")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `__getitem__`\n",
    "\n",
    "使得实例可以通过按照取下标的方式取出元素"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "f[0]:  1\n",
      "f[10]:  89\n",
      "f[100]:  573147844013817084101\n",
      "f[:10]:  [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]\n"
     ]
    }
   ],
   "source": [
    "class Fib(object):\n",
    "    def __getitem__(self, n):\n",
    "        # n是索引\n",
    "        if isinstance(n, int):\n",
    "            a, b = 1, 1\n",
    "            for x in range(n):\n",
    "                a, b = b, a+b\n",
    "            return a\n",
    "        # n是切片\n",
    "        if isinstance(n, slice):\n",
    "            start = n.start\n",
    "            stop = n.stop\n",
    "            \n",
    "            if start is None:\n",
    "                start = 0\n",
    "                \n",
    "            a, b = 1, 1\n",
    "            L = []\n",
    "            for x in range(stop):\n",
    "                if x >= start:\n",
    "                    L.append(a)\n",
    "                a, b = b, a+b\n",
    "            return L\n",
    "    \n",
    "f = Fib()\n",
    "print(\"f[0]: \", f[0])\n",
    "print(\"f[10]: \", f[10])\n",
    "print(\"f[100]: \", f[100])\n",
    "print(\"f[:10]: \", f[0:10])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `__getattr__`\n",
    "\n",
    "给class不存在的属性和接口提供默认值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "s.name:  Michael\n",
      "s.score:  99\n",
      "s.age():  25\n"
     ]
    },
    {
     "ename": "AttributeError",
     "evalue": "'Student' object has no attribute 'grade'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-13-6fa0ba4a2cff>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m     15\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"s.score: \"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0ms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mscore\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     16\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"s.age(): \"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0ms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mage\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 17\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"s.grade: \"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0ms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgrade\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m<ipython-input-13-6fa0ba4a2cff>\u001b[0m in \u001b[0;36m__getattr__\u001b[0;34m(self, attr)\u001b[0m\n\u001b[1;32m      9\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mattr\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m'age'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     10\u001b[0m             \u001b[0;32mreturn\u001b[0m \u001b[0;32mlambda\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;36m25\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m         \u001b[0;32mraise\u001b[0m \u001b[0mAttributeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'\\'Student\\' object has no attribute \\'%s\\''\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     12\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     13\u001b[0m \u001b[0ms\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mStudent\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mAttributeError\u001b[0m: 'Student' object has no attribute 'grade'"
     ]
    }
   ],
   "source": [
    "class Student(object):\n",
    "\n",
    "    def __init__(self):\n",
    "        self.name = 'Michael'\n",
    "\n",
    "    def __getattr__(self, attr):\n",
    "        if attr == 'score':\n",
    "            return 99\n",
    "        if attr == 'age':\n",
    "            return lambda: 25\n",
    "        raise AttributeError('\\'Student\\' object has no attribute \\'%s\\'' % attr)\n",
    "        \n",
    "s = Student()\n",
    "print(\"s.name: \", s.name)\n",
    "print(\"s.score: \", s.score)\n",
    "print(\"s.age(): \", s.age())\n",
    "print(\"s.grade: \", s.grade)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `__call__`\n",
    "\n",
    "把一个类实例当做函数一样调用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "My name is Mick.\n"
     ]
    }
   ],
   "source": [
    "class Student(object):\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "\n",
    "    def __call__(self):\n",
    "        print('My name is %s.' % self.name)\n",
    "        \n",
    "s = Student(\"Mick\")\n",
    "s()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## callable\n",
    "\n",
    "判断对象是否可调用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "True\n",
      "False\n",
      "False\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "print(callable(Student(\"mick\")))\n",
    "print(callable(max))\n",
    "print(callable([1, 2, 3]))\n",
    "print(callable(None))\n",
    "print(callable('str'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
